package com.zhuoyue.common.aop.count;

import com.zhuoyue.common.aop.auth.User;
import com.zhuoyue.common.jwt.util.JwtOperator;
import com.zhuoyue.common.utils.AtomicCounter;
import com.zhuoyue.common.utils.IpUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * API访问历史统计
 *
 * @author yangjunqiang
 */
@Component
@Aspect
@Slf4j
public class ApiVisitHistory {
    @Value("${topic.rabbit.userReqCount}")
    private String userReqCount;
    private static final String BEARER = "Bearer ";
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private JwtOperator jwtOperator;

    private static final int HEAD_SIZE = 10;

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 定义切面
     * - 此处代表com.smile.demo.controller包下的所有接口都会被统计
     */
    @Pointcut("execution(* com.zhuoyue.web.controller..*.*(..))")
    public void pointCut() {

    }

    /**
     * 在接口原有的方法执行前，将会首先执行此处的代码
     */
//    @Before("pointCut()")
//    public void doBefore(JoinPoint joinPoint) throws Throwable {
//        startTime.set(System.currentTimeMillis());
//        //获取传入目标方法的参数
//        Object[] args = joinPoint.getArgs();
//        log.info("类名：{}", joinPoint.getSignature().getDeclaringType().getSimpleName());
//        log.info("方法名:{}", joinPoint.getSignature().getName());
//        // 计数
//        AtomicCounter.getInstance().increase();
//    }

    /**
     * 只有正常返回才会执行此方法
     * 如果程序执行失败，则不执行此方法
     */
    @AfterReturning(returning = "returnVal", pointcut = "pointCut()")
    public void doAfterReturning(JoinPoint joinPoint, Object returnVal) {
        Map<String, Object> map = new HashMap<>(2);
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        User user = (User) request.getAttribute("user");
        if (user != null) {
            map.put("userId", user.getId());
            map.put("account", user.getAccount());
            map.put("orgCode", user.getOrgCode());
            map.put("phoneType", user.getSourceType());
            rabbitTemplate.convertAndSend(userReqCount, map);
        }
        if (user == null) {
            String tokenStr = request.getHeader("Authorization");
            if (StringUtils.isEmpty(tokenStr) || tokenStr.length() < HEAD_SIZE) {
                return;
            }
            String token = null;

            if (tokenStr.startsWith(BEARER)) {
                token = tokenStr.substring(7);
            }
            try {
                Boolean isValid = jwtOperator.validateToken(token);
                if (isValid) {
                    //3.如果校验成功，就将用户的信息设置到request的attribute里面
                    Claims claims = jwtOperator.getClaimsFromToken(token);
                    String idStr = claims.get("id").toString();
                    String account = (String) claims.get("account");
                    String orgCode = claims.get("orgCode").toString();
                    Integer sourceType = (Integer) claims.get("sourceType");
                    map.put("userId", idStr);
                    map.put("account", account);
                    map.put("orgCode", orgCode);
                    map.put("phoneType", sourceType);
                    rabbitTemplate.convertAndSend(userReqCount, map);
                }
            } catch (Exception e) {

            }


        }

//        log.info("所有接口的总点击:{}", AtomicCounter.getInstance().getValue());
    }

    /**
     * 当接口报错时执行此方法
     */
//    @AfterThrowing(pointcut = "pointCut()")
//    public void doAfterThrowing(JoinPoint joinPoint) {
//        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//        log.info("接口访问失败，URI:[{}], 耗费时间:[{}] ms", request.getRequestURI(), System.currentTimeMillis() - startTime.get());
//    }

}